/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package aso.upna.net;

import aso.upna.cancion.CancionLocal;
import aso.upna.cancion.CancionRemota;
import aso.upna.config.ClientConfig;
import aso.upna.filesystem.SharedFolder;
import aso.upna.playlist.GenericIterator;
import aso.upna.playlist.GenericList;
import aso.upna.rmi.UserHandler;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.RemoteException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author triki
 */

public class ConnectionProtocol {

    private Socket sock;
    private ConnectionSettings c_set;
    private SharedFolder shared_fol;
    private ClientConfig cfg;

    private ObjectInputStream ois;
    private ObjectOutputStream oos;

    private final int NO_STATE = -1;
    private final int LOGIN_STATE = 0;
    private final int SHARED_STATE = 1;
    private final int CONNECTED_STATE = 2;

    private int current_state;

    public ConnectionProtocol(ConnectionSettings settings,ClientConfig conf,SharedFolder shared)
    {
        c_set = settings;
        cfg = conf;
        shared_fol = shared;
        current_state = LOGIN_STATE;
    }

    public boolean connection_open()
    {
        try
        {
            String user = c_set.getUser();
            String pass = c_set.getPassword();
      
            UserHandler ser = (UserHandler) Naming.lookup("rmi://"+c_set.getIp()+":1084/perfiles");
            
            if(!ser.checkLogin(user, pass))
                return false;
            else
            {
                System.out.println("Objeto remoto ejecutado.");
            }
            
            System.out.println("connecting to "+c_set.getIp()+" ("+c_set.getPort()+")");
            sock = new Socket(c_set.getIp(),c_set.getPort());

            oos = new ObjectOutputStream(sock.getOutputStream());
            ois = new ObjectInputStream(sock.getInputStream());
            
            return true;
        }
        catch (NotBoundException ex)
        {
            ex.printStackTrace();
            return false;
        }
        catch (MalformedURLException ex)
        {
            ex.printStackTrace();
            return false;
        }
        catch (RemoteException ex)
        {
            ex.printStackTrace();
            return false;
        }
        catch (UnknownHostException ex)
        {
            ex.printStackTrace();
            return false;
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
            return false;
        }
    }

    public boolean connection_logon()
    {
        Object aux = null;
        {
            UserHandler ser = null;
            
            try
            {
                String user = c_set.getUser();
                String pass = c_set.getPassword();
                int port = cfg.getTcpPort();
                
                WellcomeMessage msg = new WellcomeMessage(user, user, pass, port);
                oos.writeObject(msg);
                aux = ois.readObject();

                if (aux instanceof RespondMessage)
                {
                    RespondMessage rep_msg = (RespondMessage) aux;
                    System.out.println("login code: "+rep_msg.getCode());
                    
                    if (rep_msg.getCode() == 0)
                    {
                        System.out.println("Exito");
                        //System.exit(0);
                        return true;
                        
                    }
                    else
                    {
                        return false;
                    }
                } 
                else
                {
                    System.out.println("** Instancia no reconocida");
                    return false;
                }
            }
            catch (ClassNotFoundException ex)
            {
                ex.printStackTrace();
                return false;
            }
            catch (IOException ex)
            {
                ex.printStackTrace();
                return false;
            }
        }
    }

    public boolean connection_sendSharedFolder()
    {
        try
        {
            GenericIterator iter = shared_fol.getIterator();
            GenericList lista = new GenericList();
            Object aux = null;

            while (iter.hasNext()) {
                CancionLocal loc = (CancionLocal) iter.current();
                CancionRemota rem = loc.getCancionRemota(c_set.getUser());
                lista.addElement(rem);
                iter.next();
            }
            
            String u_id = new String(""+c_set.getUser());
            SharedSongMessage msg = new SharedSongMessage(u_id, lista);
            
            oos.writeObject(msg);
            System.out.println("Objeto enviado");
            aux = ois.readObject();
            System.out.println("Leida");
            if (aux instanceof RespondMessage)
            {
                RespondMessage rep_msg = (RespondMessage) aux;
                
                if (rep_msg.getCode() == 0)     //EXITO
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                System.out.println("** Instancia no reconocida");
                return false;
            }

        }
        catch (ClassNotFoundException ex)
        {
            ex.printStackTrace();
            return false;
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
            return false;
        }
    }

    public boolean connection_starts()
    {
        if(!connection_open())
            return false;

        System.out.print("Comienza la negociacion");
        while(current_state != CONNECTED_STATE)
        {
            switch(current_state)
            {
                case LOGIN_STATE:
                {
                    if(connection_logon())
                    {
                        System.out.append("Estoy aqui");
                        current_state = SHARED_STATE;
                    }
                    else
                    {
                        System.out.print("ENTRA X EL CULO");
                        disconnect();
                        return false;
                    }
                }
                break;
                case SHARED_STATE:
                {
                    if(connection_sendSharedFolder())
                        current_state = CONNECTED_STATE;
                    else
                    {
                        disconnect();
                        return false;
                    }
                }
            }
        }
        return true;
    }

    public GenericList remoteSearch(String pattern)
    {
        GenericList lista = null;
        Object aux = null;

        if (!is_connected())
        {
            return null;
        }

        SearchQueryMessage msg = new SearchQueryMessage(pattern);

        try 
        {
            oos.writeObject(msg);
            aux = ois.readObject();

            if(aux instanceof GenericListMessage) //La busqueda ha surtido efecto.
            {
                GenericListMessage res = (GenericListMessage)aux;
                lista = res.getLista();
                
                return lista;
            }

            if(aux instanceof RespondMessage) //ha habido algun error.
            {
                RespondMessage res = (RespondMessage)aux;
                System.out.println("Busqueda remota. Code: "+res.getCode());
                return null;
            }

            return null;
        }
        catch (ClassNotFoundException ex)
        {
            ex.printStackTrace();
            return null;
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
            return null;
        }
    }

    public UserInfoMessage user_lookup(String u_id,String cancion)
    {
        Object aux = null;

        if (!is_connected())
        {
            return null;
        }

        LookUpMessage msg = new LookUpMessage(u_id,cancion);

        try
        {
            oos.writeObject(msg);
            aux = ois.readObject();

            if(aux instanceof UserInfoMessage) //La busqueda ha surtido efecto.
            {
                UserInfoMessage res = (UserInfoMessage)aux;
                return res;
            }

            if(aux instanceof RespondMessage) //ha habido algun error.
            {
                RespondMessage res = (RespondMessage)aux;
                System.out.println("User_lookup. Code: "+res.getCode());
                return null;
            }

            return null;
        }
        catch (ClassNotFoundException ex)
        {
            ex.printStackTrace();
            return null;
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
            return null;
        }
    }

    public boolean is_connected()
    {
        if(current_state == CONNECTED_STATE)
            return true;
        return false;
    }

    public void disconnect()
    {
        System.out.println("LLAMADA A DISCONECT");

        try {
            sock.close();
        } catch (IOException ex) {
            Logger.getLogger(ConnectionProtocol.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
